;;/////////////////////////////////////////////////////////////////////////////
;; ============================================================================
;; Copyright (c) 2023 by TDK-Micronas GmbH
;; ============================================================================
;;/////////////////////////////////////////////////////////////////////////////
;;  FILE:       SafeEnaADC.s
;;  COMPANY:	TDK-Micronas GmbH
;;  DEPT:       Design Center Munich 
;;  CREATION:   09.08.2023
;;/////////////////////////////////////////////////////////////////////////////
;; SW workaround to avoid Flash ECC errors after enabling the ADC
;; 
;; After enabling the ADC, access to the Flash main array is avoided
;; long enough to allow the internal voltages to settle by jumping into
;; a ROM utility function at a reduced CPU clock speed.
;; As the utility function is called with a wrong control word, no actual
;; programming operation will be performed.
;; After returning from the utility function, the CPU clock is switched
;; back to full speed (CPUDIV=0) before the function exits.
;; 
;; The SafeEnaADC function executes the following steps:
;; - disable all interrupts
;; - read ADC->CR
;; - Set SYSCTRL->CPUDIV=3
;; - set ADC->CR_b.EN=1
;; - call WRITE_WORD (with EEPROM array address but wrong control word)
;; - set SYSCTRL->CPUDIV=0
;; - re-enable interrupts
;;/////////////////////////////////////////////////////////////////////////////

	AREA    |.text|, CODE, READONLY

SafeEnaADC	PROC
	EXPORT SafeEnaADC
	PUSH     {r0,r1,r2,lr}

; disable all interrupts
	CPSID 	 F

; read ADC->CR
	LDR      R1,=0x40006000			; r1=0x40006000 (base address of ADC)
	LDR      R2,[R1,#0x00]			; r2=ADC->CR

; set SYSCTRL->CPUDIV=3
	MOVS     R0,#0x03				; r0=0x00000003
	LDR      R1,=0x40000000			; r1=0x40000000 (base address of SYSCTRL)
	STR      R0,[R1,#0x04]			; set SYSCTRL->CPUDIV=0x00000003

; set ADC->CR_b.EN=1
	MOVS     R0,#0x01				; r0=0x00000001
	ORR		 R2,R2,R0				; r2=ADC->CR | 0x01  (set EN flag)
	LDR      R1,=0x40006000			; r1=0x40006000 (base address of ADC)
	STR      R2,[R1,#0x00]			; set ADC->CR_b.EN=0x00000001 (enable ADC)

; call WRITE_WORD(word_address, data, control_word, command)
; word_address (R0) = 0x002A0000 (address in EEPROM array)
; data (R1)			= don't care (nothing is written)
; control_word (R2) = 0x00000201 (wrong control word)
; command (R3)		= don't care (nothing is written)
	MOV      R0,#0x2A0000			; r0=0x002A0000 (word_address)	--> address in EEPROM array		
	MOVW     R2,#0x201				; r2=0x00000201 (jump address of WRITE_WORD utility function), also (wrong) control_word
	BLX      R2						; call WRITE_WORD(0x002A0000, 0xXXXXXXXX, 0x00000201, 0xXXXXXXXX)

; set SYSCTRL->CPUDIV=0
	LDR      R1,=0x40000000			; r1=0x40000000 (base address of SYSCTRL)
	MOVS     R0,#0x00				; r3=0x00000000
	STR      R0,[R1,#0x04]			; set SYSCTRL->CPUDIV=0x00000000			

; re-enable interrupts
	CPSIE 	 F

	POP      {r0,r1,r2,pc}
	ENDP


	END
